﻿using System;
using System.Collections.Generic;

namespace Tracker
{
  public struct Vector_2
  {
    Vector_2(double vx, double vy)
    {
      vx_ = vx;
      vy_ = vy;
    }

    public double Length
    {
      get
      {
        return Math.Sqrt(vx_*vx_+vy_*vy_);
      }
    }

    public double Length2
    {
      get
      {
        return vx_ * vx_ + vy_ * vy_;
      }
    }

    public int Theta
    {
      get
      {
        return Angle.DegreeInt(VX, VY);
      }
    }

    public Vector_2 Normalize()
    {
      return this / Length;
    }

    public Vector_2 Rotate(int a)
    {
      double kSin = Angle.Sin(a);
      double kCos = Angle.Cos(a);

      return new Vector_2(VX * kCos - VY * kSin, VX * kSin + VY * kCos);
    }

    public static Vector_2 operator -(Vector_2 vec)
    {
      return new Vector_2(-vec.VX, -vec.VY);
    }

    public static Vector_2 operator ~(Vector_2 vec)
    {
      return new Vector_2(-vec.VY, vec.VX);
    }

    public static Vector_2 operator +(Vector_2 lvec, Vector_2 rvec)
    {
      return new Vector_2(lvec.VX+rvec.VX, lvec.VY+rvec.VY);
    }

    public static Vector_2 operator -(Vector_2 lvec, Vector_2 rvec)
    {
      return new Vector_2(lvec.VX - rvec.VX, lvec.VY - rvec.VY);
    }

    public static Vector_2 operator *(Vector_2 vec, double s)
    {
      return new Vector_2(vec.VX * s, vec.VY * s);
    }

    public static Vector_2 operator *(double s, Vector_2 vec)
    {
      return new Vector_2(vec.VX * s, vec.VY * s);
    }

    public static double operator *(Vector_2 lvec, Vector_2 rvec)
    {
      return lvec.VX * rvec.VX + lvec.VY * rvec.VY; 
    }

    public static double operator |(Vector_2 lvec, Vector_2 rvec)
    {
      return lvec.VX * rvec.VY - lvec.VY * rvec.VX;
    }

    public static Vector_2 operator /(Vector_2 vec, double s)
    {
      return new Vector_2(vec.VX / s, vec.VY / s);
    }

    public bool Left(Vector_2 vec)
    {
      return (vec | this) > 0;
    }

    public bool Right(Vector_2 vec)
    {
      return (vec | this) < 0;
    }

    public bool Acute(Vector_2 vec)
    {
      return (this * vec) > 0;
    }

    public bool Obtuse(Vector_2 vec)
    {
      return (this * vec) < 0;
    }

    public double VX
    {
      get
      {
        return vx_;
      }
    }

    public double VY
    {
      get
      {
        return vy_;
      }
    }

    private readonly double vx_;
    private readonly double vy_;
  }
}
